#ifndef DEF_HEADER
#define DEF_HEADER

#include<string>
#include<fstream>
#include<sstream>
#include<iostream>
#include<algorithm>
#include<iterator>
#include<vector>
#include<map>
#include<cstdlib>
#include<ctime>
#include<cmath>
#include <gsl/gsl_rng.h>
#include <gsl/gsl_randist.h>

using namespace std;

/* Main Definitions */
enum ModelType{
  MODEL_GENERATOR,
  MODEL_ESTIMATOR,
  MODEL_TOPICMODEL,
  MODEL_ERROR
};

enum EstimatorType{
  EST_POLYA,
  EST_ERROR
};

enum GeneratorType{
  GE_MULTINOMIAL,
  GE_DIRICHLET,
  GE_POLYA,
  GE_ERROR
};

enum InputType{
  INPUT_TEXT,
  INPUT_BUFFER_PROTOCOL, 
  INPUT_ERROR
};

enum OutputType{
  OUTPUT_TEXT,
  OUTPUT_BUFFER_PROTOCOL,
  OUTPUT_ERROR
};

enum TopicModelType{
  TOPICMODEL_LDA_GIBBS_SAMPLING,
  TOPICMODEL_LDA_VARIATIONAL_BAYES,
  TOPICMODEL_LDA_VARIATIONAL_BAYES_ONLINE,
  TOPICMODEL_AT_BATCH,
  TOPICMODEL_AT_ONLINE,
  TOPICMODEL_TOT,
  TOPICMODEL_GEO_SIMPLE_1_BATCH,
  TOPICMODEL_GEO_SIMPLE_1_ONLINE,
  TOPICMODEL_GEO_CLUSTER_BATCH,
  TOPICMODEL_GEO_MF_BATCH,
  TOPICMODEL_GEO_MF_TOPIC,
  TOPICMODEL_GEO_MF_TOPIC_BACK,
  TOPICMODEL_GEO_MF_TOPIC_GEO_BACK,
  TOPICMODEL_GEO_MF_ONLINE,
  TOPICMODEL_GEO_MF_LOC,
  TOPICMODEL_GEO_MF_LOC_BACK,
  TOPICMODEL_ERROR
};

enum TopicModelTaskType{
  TOPICMODEL_TASK_INFERENCE,
  TOPICMODEL_TASK_PREDICTION,
  TOPICMODEL_TASK_INFERENCE_AND_PREDICTION,
  TOPICMODEL_TASK_INTERACTIVE,
  TOPICMODEL_TASK_ERROR
};

typedef struct TermItemStruct{
  int term_id;
  int term_stat;
}TermItem;

enum PolyaEstimatorType{
  EST_POLYA_SGD,
  EST_POLYA_NEWTON,
  EST_POLYA_FIXEDPOINT,
  EST_POLYA_ERROR
};

enum GeoValueType{
  GEO_TYPE_DISCRETE,
  GEO_TYPE_REAL
};

typedef vector<TermItem> TermList;
typedef vector<TermList> DocList;

typedef int(*ModelFunc)();
typedef map<int,string> IdMapping;
typedef map<int,double> TimeMapping;
typedef map<int,double> GeoTermItem;
typedef vector<GeoTermItem> GeoTerms;


class PuzaDEF{
public:
  static PuzaDEF* Instance();

  /* Global Variables */
  ModelType currentModelType;
  string input_file_name;
  string train_file_name;
  string test_file_name;
  string output_file_name;
  ifstream InputFile;
  ofstream LogFile;
  InputType currentInputType;
  OutputType currentOutputType;
  IdMapping data_ids;
  TimeMapping data_timestamps;
  
  /* Topic Model Variables */
  TopicModelType currentTopicModelType;
  TopicModelTaskType currentTopicModelTaskType;
  int** TM_Doc;
  int DOC_NUM;
  int TOPIC_NUM;
  int TERM_NUM;
  int AUTHOR_NUM;
  double* LDA_alpha;
  double* LDA_beta;
  double LDA_initial_alpha;
  double LDA_initial_beta;
  int BatchSize;
  double LDA_VBONLINE_tau0;
  double LDA_VBONLINE_kappa;
  int GEO_REGION_NUM;
  int GEO_USER_NUM;
  double GEO_LEARNING_RATE;
  double GEO_REG;
  int GEO_REG_TYPE;
  int GEO_REG_L1_K;
  double GEO_REG_L1_G;
  GeoValueType GEO_TYPE;
  int GEO_M_ITER;
  int GEO_E_ITER;

  /* Estimator Variables */
  EstimatorType currentEstimatorType;
  PolyaEstimatorType currentPolyaEstimatorType;
  int** EST_BUFFER_INT;
  double** EST_BUFFER_DOUBLE;
  int EST_Samples;
  int EST_Polya_K;
  double EST_Polya_SGD_Initial_Rate;

  /* Generator Variables */
  GeneratorType currentGeneratorType;
  int GE_Samples;
  
  int GE_Multinomial_K;
  int GE_Multinomial_N;
  double* GE_Multinomial_P;
  unsigned int* GE_Multinomial_Data;
  
  int GE_Dirichlet_K;
  double GE_Dirichlet_Alpha;
  double* GE_Dirichlet_Base;
  double* GE_Dirichlet_Data;
  
  int GE_Polya_K;
  int GE_Polya_N;
  double GE_Polya_Alpha;
  double* GE_Polya_Base;
  unsigned int* GE_Polya_Data;
  
  gsl_rng *gBaseRand;
  unsigned long randSeed;
private:
  PuzaDEF();  // private so that it can  not be called                                                                                                    
  PuzaDEF(PuzaDEF const&){}; // copy constructor is private                                                                                                
  static PuzaDEF* m_pInstance;
};
#endif
